#include "nrtypes.h"
#include <cstdlib>
#include <cstdio>
#include <cstring>

#define NPOINTS 84
#define TICK 100

QWORD *F;
QWORD *B;
QWORD *T;
QWORD *S;

FILE *input, *output;

int slen;
int nbits;
int	len;
int L, t;

void init ()
{
	fseek(input, 0, SEEK_END);
	slen = ftell(input);
	fseek(input, 0, SEEK_SET);
	len = slen/sizeof(QWORD) + 1;
	S = (QWORD*)calloc(sizeof(QWORD), len);
	F = (QWORD*)calloc(sizeof(QWORD), len);
	T = (QWORD*)calloc(sizeof(QWORD), len);
	B = (QWORD*)calloc(sizeof(QWORD), len);
	nbits = sizeof(QWORD) * 8;
	memset(F, 0, slen);
	memset(T, 0, slen);
	int n = slen;
	do 
	{
		n -= fread(S, sizeof(BYTE), n, input);
	}
	while (n);
	fclose(input);
}

#define BIT(i, f) ( (f[(i)/nbits]>>((i)%nbits)) &  1)

int deltar(int r)
{
	int j;
	QWORD s = 0;
	for(j=0; j<=L; j++)
		s ^= BIT(j, F) & BIT(r - j, S);
	return !!s;
}

void shpl(QWORD *A, QWORD *B)
{
	QWORD c = 0;
	int j, N;
	c = 0;
	N = (L > t ? L + 1 : t + 1);
	N/=nbits;
	N++;
	for (j=0; j<N; j++)
	{
		A[j] ^= (B[j]<<1) | c;
		c = (B[j]>>(nbits-1)) & 1;
	}
}

void sh(QWORD *A)
{
	QWORD c, c1;
	int j, N;
	c = 0;
	N = (L > t ? L + 1 : t + 1);
	N/=nbits;
	N++;
	for (j=0; j<N; j++)
	{
		c1 = (A[j]>>(nbits-1)) & 1;
		A[j] = (A[j]<<1) | c;
		c = c1;
	}
}

void outf(int r)
{
	int i, N = L/nbits + (L % nbits ? 1 : 0);
	printf("L[%d] = %d\n", r, L);
	fprintf(output, "%d;%d;f(x): ", r, L);
	for (i=N-1; i>=0; i--)
		fprintf(output, "%I64X", F[i] );
	fprintf(output, "\n" );
}

int lastPoint = 0;

void evaluateComplexity()
{
	int r, d, dr, N, t, dpoint;
	L = 0;
	F[0] = T[0] = 1;
	N = slen * 8;
	t = 0;
	dpoint = TICK;//N / NPOINTS;
	for(r=1; r<N; r++)
	{
		if (dr = deltar(r))
		{
			if (2*L <= r-1)
			{
				d = 1;
				L = r - L;
				lastPoint = r;
			}
			else
				d = 0;
			memcpy(B, F, slen);
			shpl(B, T);
		}
		else
			d = 0;
		if(d)
		{
			memcpy(T, F, slen);
			t = L;
		}
		else
		{
			sh(T);
			t++;
		}
		if (dr)
			memcpy(F, B, slen);
		if (r%dpoint == 0)
			outf(r);
	}
	outf(r);
	fprintf(output, "last change: %d", lastPoint);
}

void printUsage()
{
	printf ("USAGE:\n\tsynthesis.exe INPUT-FILE [OUTPUT-FILE]\ndefault value for OUTPUT-FILE is \"synthesis.csv\"");
}

int main(int argc, char* argv[])
{
	if(argc == 1 || argc > 3)
	{
		printUsage();
		return 0;
	}
	input = fopen ( argv[1], "rb");
	if ( input == NULL )
	{
		printf ("cannot open input file \"%s\" for reading", argv[1]);
		return 0;
	}
	char str[1024];
	strcpy(str, argc > 2 ? argv[2] : "synthesis.csv");
	output = fopen (str, "w");
	if ( output == NULL )
	{
		printf ("cannot open file \"%s\" for writing", str);
		return 0;
	}

	init ();
	evaluateComplexity();
	fclose(output);
	return 0;
}